/////////////////////////////////////////////////////////////////////////////
/*
  Copyright 2001,2002,2003,2004 Ronald S. Burkey. <info@sandroid.org>
  Copyright 2001 Joe Cherry.

  This file is part of GutenMark.

  GutenMark is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  GutenMark is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with GutenMark; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

  Filename:	OutputLatex.c 
  Purpose:	Outputs the LaTeX file.
  Mods:		01/13/02 RSB	Split off from AutoMark.c
  		06/15/02 RSB	Eliminated the arbitrary addition of 
				"Chapter 1", "Chapter 2", etc., at the 
				section breaks.  Added stuff for 
				ISO8859-1 characters in the numerical
				range 0x80-0xFF. 
		06/16/02 RSB	Fixed up page headings.  No longer creates
				a table of contents.  (This is related
				to the problem of adding "Chapter 1" etc.
				fixed yesterday.  Doesn't seem to be any
				way to create the table of contents 
				without this extra crap.)  Now no longer 
				outputs carriage returns at all (it only
				outputs the linefeeds) to accomodate some
				wacky files that contained constructs
				like ^M^M.	
		08/03/02 RSB	Now eliminate periods and spaces (but not
				ellipses) at the ends of chapter names.	
				Added an "emergencystrech" command, to 
				account for the fact that an annoying 
				number of lines run into the right margin
				with the default settings and small page
				sizes.  Removed the soft-hypen in LaTeX.
				Fixed the problem of honorifics being
				treated as ends of sentences.
		08/04/02 RSB	Chapter headings are now ragged-right.
				Also, outputting the hard space is 
				eliminated, because it's unnecessary
				for forcing extra spaces between sentences.
				Provided a partial fix (I hope) for the
				problem of a line-break appearing within
				italicized text.  Also, the "-%" added
				yesterday after em-dashes is now 
				eliminated when in italics where, for some
				reason, it causes a problem.
				... Later:  *Sigh!*  Failure of thought
				alarm!  '%' is a comment symbol, so 
				"-%" will simply eliminate everything
				to the end of the line.  Duh!	
		08/05/02 RSB	Added LatexSections.	
		08/08/02 RSB	Added tables of contents, and accounted
				for the --no-toc, --title, and --author
				options.
		08/10/02 RSB	Fixed a segfault in the new author-deduction
				code that could occur if it can't find the 
				author name.
		08/11/02 RSB	\\protect removed from \\raggedright.
				It doesn't seem to be necessary, and
				lyx 1.2 messes it up.  Similarly for the
				\\global in front of \\emergencystretch.
				Added braces to some special-character
				sequences like \\ae, because otherwise 
				they don't seem to be recognized.
		08/25/02 RSB	\emergencystretch replaced with \sloppy.
				Hard spaces are no longer used in chapter
				headings.  On the page headings, now
				force the right-hand one to be ALL-CAPS
				if the left one is, and vice-versa.
				Also for page headings, when the 
				heading is something like 
				"CHAPTER X. SOMETHING", we chop off the
				"CHAPTER X." part.
		11/14/02 RSB	Hopefully, fixed up the 1-space vs. 2-space
				problem.
		11/22/02 RSB	Added raggedbottom as the default.  Hopefully,
				fixed the missing quotes in chapter names.  
				Added an mbox around mdashes, and allow the
				mdash to have an adjustable size. Uses of 
				"~" have been replaced by "\\ ".
		12/23/02 RSB	Changed the mbox protection for mdashes, to
				add a linebreak suggestion.  This has been
				done as a macro because lyx doesn't correctly
				import "\mbox{----}\linebreak[1]".  Also, 
				eliminated the date from the title page.
		12/25/02 RSB	Various messages like "this was created by 
				GutenMark" have been moved from the "prefatory
				materials" to the copyright area behind the
				title page.  Also, added stuff pertaining to 
				the "--ron" switch.
		12/28/02 RSB	LyX (1.2) has a problem importing multiple
				juxtaposed commands, like "\ \ \ ", in that it
				artibrarily inserts a line-feed in between.
				There's nothing I can do about this in general,
				but in the specific case of multiple "\ ", I 
				convert the second (and beyond) "\ " to "~".
		01/05/03 RSB	*Sigh!*  I've been using the wrong construct 
				for the mdash all this time.  It should simply
				have been --- (with no mbox, no linebreak, etc.)
		01/21/04 RSB	Fixed a messed-up comment that generated warnings.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <zlib.h>
#include <time.h>
#include "AutoMark.h"

//--------------------------------------------------------------------------
// 06/15/02 RSB.
// Characters with diacriticals et al.  Each ISO8859-1 character 
// is converted instead to a string.  These aren't always right,
// but they're the best I can see how to do at the moment. 
// Entries which are NULL mean "don't translate the character". 

static const char *ISO88591[256] = {
  "", "", "", "", "", "", "", "",
  "", "", NULL, "", "", "", "", "",
  "", "", "", "", "", "", "", "",
  "", "", "", "", "", "", "", "",
  NULL, NULL, NULL, "\\#", "\\$", "\\%%", "\\&", NULL,
  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  NULL, NULL, NULL, NULL, "$<$", NULL, "$>$", NULL,
  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  NULL, NULL, NULL, NULL, "$\\backslash$", NULL, "\\verb.^.", "\\_",
  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  NULL, NULL, NULL, "\\{", "$|$", "\\}", "\\verb.~.", "",
  "", "", "", "", "", "", "", "",
  "", "", "", "", "", "", "", "",
  "", "", "", "", "", "", "", "",
  "", "", "", "", "", "", "", "",
  "", "<", " cents ", "\\pounds",
  "", " Yen ", "$|$", "\\S",
  "\\\"{ }", "\\copyright", "$^{\\underline{a}}$", "$\\ll$",
  "", "", " (R) ", "\\={ }",
  "$^{\\circ}$", "$\\pm$", "$^{2}$", "$^{3}$",
  "\\\'{ }", "$\\mu$", "\\P", "$\\cdot$",
  "\\c{ }", "$^{1}$", "$^{\\underline{o}}$", "$\\gg$",
  " 1/4", " 1/2", " 3/4", ">",
  "\\`{A}", "\\\'{A}", "\\^{A}", "\\~{A}",
  "\\\"{A}", "{\\AA}", "{\\AE}", "\\c{C}",
  "\\`{E}", "\\\'{E}", "\\^{E}", "\\\"{E}",
  "\\`{I}", "\\\'{I}", "\\^{I}", "\\\"{I}",
  "D", "\\~{N}", "\\`{O}", "\\\'{O}",
  "\\^{O}", "\\~{O}", "\\\"{O}", "$\\times$",
  "\\O", "\\`{U}", "\\\'{U}", "\\^{U}",
  "\\\"{U}", "\\`{Y}", "P", "\\ss{}",
  "\\`{a}", "\\\'{a}", "\\^{a}", "\\~{a}",
  "\\\"{a}", "{\\aa}", "{\\ae}", "\\c{c}",
  "\\`{e}", "\\\'{e}", "\\^{e}", "\\\"{e}",
  "\\`{\\i}", "\\\'{\\i}", "\\^{\\i}", "\\\"{\\i}",
  "d", "\\~{n}", "\\`{o}", "\\\'{o}",
  "\\^{o}", "\\~{o}", "\\\"{o}", "$\\div$",
  "\\o", "\\`{u}", "\\\'{u}", "\\^{u}",
  "\\\"{u}", "\\\'{y}", "p", "\\\"{y}"
};

//--------------------------------------------------------------------------
// Given two strings, if either one is ALL-CAPS, forces the other one to
// be all-caps also.

static void
ForceCase (char *s1, char *s2)
{
  int NumUp, NumLow;
  char *s;
  // First, check string 1.
  for (s = s1, NumUp = NumLow = 0; *s; s++)
    if (isupper (*s))
      NumUp++;
    else if (islower (*s))
      NumLow++; 
  if (NumUp && !NumLow)   
    {
      for (s = s2; *s; s++)
        *s = toupper (*s);
      return;	
    }
  // Then check string 2.
  for (s = s2, NumUp = NumLow = 0; *s; s++)
    if (isupper (*s))
      NumUp++;
    else if (islower (*s))
      NumLow++; 
  if (NumUp && !NumLow)   
    {
      for (s = s1; *s; s++)
        *s = toupper (*s);
      return;	
    }
}

//--------------------------------------------------------------------------
// Given a string of the form "CHAPTER X. SOMETHING" (with "SOMETHING" not
// merely a blank space) changes it to "SOMETHING".

static int
IsTermPunct (char c)
{
  return (c == '.' || c == ',' || c == ':' || c == ';' || c == '-');
}

static void
ChopChapter (char *s)
{
  char *ss;
  // Eliminate any leading space.
  for (ss = s; isspace (*ss); ss++);
  if (!*ss)
    return;
  // Does what's left begin with "CHAPTER"?
  if (strncasecmp (ss, "CHAPTER ", 8))
    return;
  // Eliminate space.
  for (ss += 8; isspace (*ss); ss++);
  if (!*ss)
    return;
  // What we should have here is a string of decimal digits or roman 
  // numerals, followed by punctuation or whitespace.
  for (; isdigit (*ss) || *ss == 'I' || *ss == 'V' || *ss == 'X' || 
        *ss == 'L' || *ss == 'C'; ss++);
  if (!isspace (*ss) && !IsTermPunct (*ss))
    return;
  // Eliminate the punctuation or whitespace.
  for (; isspace (*ss) || IsTermPunct (*ss); ss++);
  if (!*ss)
    return;
  // Wow, finally we're here!  ss points t the actual chapter title.
  for (; *ss; *s++ = *ss++);
  *s = 0;              	             
}

//--------------------------------------------------------------------------

static char Chapter[256];
static int ChapterNameSize = 0;

static void
OutputChar (FILE * OutputFile, int c, int InChapter)
{
  if (ISO88591[c] == NULL)
    {
      if (InChapter == 1 && (c == '\r' || c == '\n'))
	c = ' ';
      if (InChapter && ChapterNameSize < (sizeof (Chapter) - 1))
	Chapter[ChapterNameSize++] = c;
      putc (c, OutputFile);
    }
  else
    {
      int Len;
      Len = ChapterNameSize + strlen (ISO88591[c]);
      if (InChapter && Len < sizeof (Chapter))
	strcpy (&Chapter[ChapterNameSize], ISO88591[c]);
      ChapterNameSize = Len;
      fputs (ISO88591[c], OutputFile);
    }
}

//--------------------------------------------------------------------------
// Handles just the output, after all analysis has been completed.
// Returns 0 on success, non-zero on error.

int
OutputLatex (FILE * OutputFile, AnalysisDataset * Dataset)
{
  time_t CurrentTime;
  int i, ErrorCode, c, lastc, Remove, AtEnd;
  MarkupRecord Mark;
  unsigned long Offset;
  char s[256], Title[256], *ss, *sss;
  int InItalics = 0;
  int InParagraph = 0;
  int InChapter = 0;
  int InPreformatted = 0, LastNewline = 1;
  int SentPgHeader = 0;
  int AfterBreak = 0;
  char *InputFilename = NULL;
  int Removed = -1;
  int JumpedPastHeader = 0;
  int InPrefatoryArea = 0;
  int lastcSize = 0;

  // Print output header.
  fprintf (OutputFile, "\\documentclass{book}\n");
  if (!Dataset->NoParskip)	// 06/15/02 RSB
    fprintf (OutputFile, "\\usepackage{parskip}\n");  
  fseek (Dataset->InputFile, 0, SEEK_SET);
  fgets (s, sizeof (s) - 1, Dataset->InputFile);
  fgets (s + strlen (s), sizeof (s) - strlen (s) - 1, Dataset->InputFile);
  NormalizeTitle (s, sizeof (s));
  // If the user has given us an author and/or title, we use it/them.
  // Otherwise, we attempt to deduce from the file.  Actually, the 
  // string labeled "Title" is itself a legacy variable, and probably not 
  // used for anything.  In most PG files, it is something like
  // "TITLE, by AUTHOR", though there are a lot of variations.
  if (Dataset->TitleBuffer[0])
    strcpy (Title, Dataset->TitleBuffer);
  else  
    strcpy (Title, s);
  // It's the Dataset->TitleBuffer and Dataset->AuthorBuffer strings
  // that really count, rather than Title.
  if (!Dataset->TitleBuffer[0] || !Dataset->AuthorBuffer[0])  
    {
      char *ss, *sss;
      for (sss = NULL, ss = s; *ss; ss++)
        if (!strncasecmp (ss, " by ", 4))
	  sss = ss;
      if (!Dataset->TitleBuffer[0] && sss != NULL)
        {
	  for (ss = sss - 1; ss > s; ss--)
	    if (*ss != ' ' && *ss != ',')
	      {
	        ss[1] = 0;
		strcpy (Dataset->TitleBuffer, s);
		break;
	      }
	}
      if (!Dataset->AuthorBuffer[0] && sss != NULL)
        {
	  for (ss = sss + 4; *ss; ss++)
	    if (*ss != ' ')
	      {
	        strcpy (Dataset->AuthorBuffer, ss);
		break;
	      }
	}		  
    }
  if (Dataset->TitleBuffer[0])
    strcpy (Title, Dataset->TitleBuffer);
  // Note that some of the tricky stuff here (like \nodate and the \newline after
  // \vspace) are not for latex as such, but rather for the purpose of fooling
  // LyX, which doesn't always work correctly when importing latex.
  if (Dataset->ron)
    {
      //fprintf (OutputFile, "\\documentclass[12pt,english]{book}\n");
      fprintf (OutputFile, "\\usepackage{newcent}\n");
      //fprintf (OutputFile, "\\usepackage[T1]{fontenc}\n");
      //fprintf (OutputFile, "\\usepackage[latin1]{inputenc}\n");
      fprintf (OutputFile, "\\usepackage{geometry}\n");
      fprintf (OutputFile, "\\geometry{verbose,paperwidth=5.5in,paperheight=8.5in,"
      			   "tmargin=0.75in,bmargin=0.75in,lmargin=1in,rmargin=1in}\n");
      //fprintf (OutputFile, "\\setcounter{secnumdepth}{3}\n");
      //fprintf (OutputFile, "\\setcounter{tocdepth}{3}\n");
    }
  fprintf (OutputFile, "\\begin{document}\n");
  fprintf (OutputFile, "\\sloppy\n");
  if (Dataset->ron)
    {
      fprintf (OutputFile, "\\evensidemargin = -0.25in\n");
      fprintf (OutputFile, "\\oddsidemargin = 0.25in\n");
    }
  fprintf (OutputFile, "\\raggedbottom\n");
  fprintf (OutputFile, "\\newcommand{\\mdsh}[1]{\\mbox{#1}\\linebreak[1]}\n");
  fprintf (OutputFile, "\\pagestyle{empty}\n");
  //fprintf (OutputFile, "\\date{}");
  fprintf (OutputFile, "\\newcommand{\\nodate}{\\date{}}\\nodate\n");
  fprintf (OutputFile, "\\title{%s}\n", Title);
  fprintf (OutputFile, "\\author{%s}\n", Dataset->AuthorBuffer);
  fprintf (OutputFile, "\\maketitle\n");
  fprintf (OutputFile, "\\vspace*{\\stretch{1}}\\newline");
  fprintf (OutputFile, "\\noindent{}The text ");
  if (InputFilename != NULL)
    fprintf (OutputFile, "(``%s\'\') ", InputFilename);  
  fprintf (OutputFile, "was converted to LaTeX by means of ");	     
  fprintf (OutputFile, "\\textbf{GutenMark} software (version " __DATE__ ").\n\n");
  time (&CurrentTime);
  for (sss = ss = ctime (&CurrentTime); *sss; sss++)
    if (*sss == '\n')
      *sss = 0;
  fprintf (OutputFile, "\\begin{center}\\noindent{}Date: %s\\end{center}\n\n", ss);
  fprintf (OutputFile, "\\vspace{\\stretch{1}}\n");
  fprintf (OutputFile, "\\frontmatter\n");
  fprintf (OutputFile, "\\pagestyle{myheadings}\n");
  if (!Dataset->NoToc)
    {
      if (Dataset->ron)
        fprintf (OutputFile, "{\\small \\tableofcontents}\n");
      else
        fprintf (OutputFile, "\\tableofcontents\n");
      fprintf (OutputFile, "\\newpage\n");
    }
  // Print marked-up text.  This is basically a matter 
  // of merging the markup file with the input file.
  fseek (Dataset->MarkupFile, 0, SEEK_SET);
  fseek (Dataset->InputFile, 0, SEEK_SET);
  if (Dataset->YesHeader)
    {
      ErrorCode = fread (&Mark, sizeof (Mark), 1, Dataset->MarkupFile);
      if (ErrorCode != 1)
	Mark.Type = MarkNoMoreMarks;
      Offset = 0;
    }
  else
    {
      do
	{
	  ErrorCode = fread (&Mark, sizeof (Mark), 1, Dataset->MarkupFile);
	  if (ErrorCode != 1)
	    {
	      Mark.Type = MarkNoMoreMarks;
	      break;
	    }
	}
      while (Mark.Offset < Dataset->TextStart);
      fseek (Dataset->InputFile, Dataset->TextStart, SEEK_SET);
      Offset = Dataset->TextStart;
    }
  for (Remove = AtEnd = c = 0;
       (lastc = c, c = fgetc (Dataset->InputFile)) != EOF; Offset++)
    {
      if (!isspace (c))
	AfterBreak = 0;
    LastShot:
      while (Offset == Mark.Offset && Mark.Type != MarkNoMoreMarks)
	{
	  switch (Mark.Type)
	    {
	    case MarkTolower:

	      //if (Removed != Offset)
	      putc (DiacriticalTolower (c), OutputFile);
	      if (InChapter && ChapterNameSize < (sizeof (Chapter) - 1))
		Chapter[ChapterNameSize++] = DiacriticalTolower (c);
	      Remove = 1;
	      break;
	    case MarkToupper:

	      //if (Removed != Offset)
	      putc (DiacriticalToupper (c), OutputFile);
	      if (InChapter && ChapterNameSize < (sizeof (Chapter) - 1))
		Chapter[ChapterNameSize++] = DiacriticalToupper (c);
	      Remove = 1;
	      break;
	    case MarkBeginSmartQuote:
	      fprintf (OutputFile, "``");
	      if (InChapter && ChapterNameSize < (sizeof (Chapter) - 2))
	        {
		  Chapter[ChapterNameSize++] = '`';
		  Chapter[ChapterNameSize++] = '`';
		}
	      Remove = 1;
	      break;
	    case MarkEndSmartQuote:
	      fprintf (OutputFile, "''");
	      if (InChapter && ChapterNameSize < (sizeof (Chapter) - 2))
	        {
		  Chapter[ChapterNameSize++] = '\'';
		  Chapter[ChapterNameSize++] = '\'';
		}
	      Remove = 1;
	      break;
	    case MarkLsquo:
	      fprintf (OutputFile, "`");
	      if (InChapter && ChapterNameSize < (sizeof (Chapter) - 1))
	        Chapter[ChapterNameSize++] = '`';
	      Remove = 1;
	      break;
	    case MarkRsquo:
	      fprintf (OutputFile, "'");
	      if (InChapter && ChapterNameSize < (sizeof (Chapter) - 1))
	        Chapter[ChapterNameSize++] = '\'';
	      Remove = 1;
	      break;
	    case MarkRemoveChar:
	      Remove = 1;
	      Removed = Offset;
	      break;
	    case MarkInsertChar:
	      //putc (Mark.Insert, OutputFile);
	      //OutputCharacter (Dataset->ForceNumeric, OutputFile, Mark.Insert);
	      OutputChar (OutputFile, Mark.Insert, InChapter);
	      break;
	    case MarkNbsp:
	      // 08/04/02 RSB.  All of the purposes for which we were using
	      // &nbsp; in HTML are basically reversed in LaTeX.  In other 
	      // words, we were using "&nbsp; " after the end of a sentence
	      // to force a longer space, and just " " after abbreviations.
	      // But LaTeX finds the ends of sentences itself, so it really
	      // needs just " " after the end of a sentence and "&nbsp;" after
	      // an abbreviation.  It adds any extra spaces itself.
	      // ... Later:  More explanation:  Where we want two spaces, the
	      // analysis has added an nbsp, presumably followed by ' '.
	      // Where we want one space, the analysis has simply left the 
	      // single space character.  Therefore, in LaTeX, nbsp-' ' should
	      // be replaced by ' '; on the other hand ' ' itself should be
	      // replaced by '~' and all subsequent spaces discarded.
	      //fprintf (OutputFile, "~");
	      if (lastc == ('~' | 0x8000))
	        {
		  lastcSize = 1;
	          fprintf (OutputFile, "~");
		}  
	      else
	        {
		  lastcSize = 2;
	          fprintf (OutputFile, "\\ ");
		}
	      if (InChapter && ChapterNameSize < (sizeof (Chapter) - 1))
		Chapter[ChapterNameSize++] = ' ';
	      lastc = '~' | 0x8000;
	      break;
	    case MarkBeginJustifiedParagraph:
	      InParagraph = 1;
	      fprintf (OutputFile, "\n\n");
	      break;
	    case MarkBeginRaggedParagraph:
	      InParagraph = 1;
	      fprintf (OutputFile, "\n\n");
	      break;
	    case MarkBeginCenteredParagraph:
	      InParagraph = 1;
              fprintf (OutputFile, "\n\n"); 
	      break;
	    case MarkEndParagraph:
	      InParagraph = 0;
	      fprintf (OutputFile, "\n\n");
 	      break;
	    case MarkBeginItalics:
	      fprintf (OutputFile, "\\textit{");
	      InItalics = 1;
	      break;
	    case MarkEndItalics:
	      fprintf (OutputFile, "}");
	      InItalics = 0;
	      break;
	    case MarkBeginBold:
	      fprintf (OutputFile, "\\textbf{");
	      break;
	    case MarkEndBold:
	      fprintf (OutputFile, "}");
	      break;
	    case MarkBeginUnderline:
	      fprintf (OutputFile, "\\emph{");
	      break;
	    case MarkEndUnderline:
	      fprintf (OutputFile, "}");
	      break;
	    case MarkBreak:
	      AfterBreak = 1;
	      // 08/04/02 RSB.
	      if (InItalics)
	        fprintf (OutputFile, "}\n\n\\textit{");
	      else
	        fprintf (OutputFile, "\n\n"); 
	      break;
	    case MarkBlockquote:	// I think, not used.
	      InParagraph = 1;
	      fprintf (OutputFile, "\\begin{quotation}\n");
	      break;
	    case MarkEndBlockquote:	// I think, not used.
	      InParagraph = 0;
	      fprintf (OutputFile, "\\end{quotation}\n");
	      break;
	    case MarkHeader1:
	      if (InPrefatoryArea)
	        {
	          InPrefatoryArea = 0;
		  fprintf (OutputFile, "\\mainmatter\n");
		}  
	      // 08/04/02 RSB.
	      if (Dataset->LatexSections)
	        fprintf (OutputFile, "\\section*{\\raggedright ");
	      else
	        fprintf (OutputFile, "\\chapter*{\\raggedright ");
	      InChapter = 1;
	      ChapterNameSize = 0;
	      break;
	    case MarkEndHeader1:
	      fprintf (OutputFile, "}\n\n");
	      InChapter = 0;
	      Chapter[ChapterNameSize] = 0;
	      // 08/03/02 RSB.  Do the following to eliminate periods
	      // (but not ellipses) at the ends of chapter names, because
	      // in LaTeX I use these as page headings and am annoyed by
	      // seeing things like "CHAPTER III." as a page heading.
	      while (ChapterNameSize > 0)
	        {
		  ChapterNameSize--;
		  if (Chapter[ChapterNameSize] == ' ' ||
		      (Chapter[ChapterNameSize] == '.' && ChapterNameSize > 1
		       && Chapter[ChapterNameSize - 1] != '.'))
		    {
		      Chapter[ChapterNameSize] = 0;
		      continue;
		    }
		  ChapterNameSize++;
		  break;		 
		}
	      if (!Dataset->LatexSections)	
	        {
		  fprintf (OutputFile, "\\addcontentsline{toc}{chapter}{%s}\n\n",
		           Chapter);
		  if (Dataset->NoToc)
		    {
		      ForceCase (Dataset->AuthorBuffer, Title);
		      fprintf (OutputFile, "\\markboth{%s}{%s}\n\n", 
			       Dataset->AuthorBuffer, Title);
		    }	     	     
		  else	   
		    {
		      ChopChapter (Chapter);
		      ForceCase (Title, Chapter);
	              fprintf (OutputFile, "\\markboth{%s}{%s}\n\n", Title, Chapter);
		    }
		}
	      else
	        {
		  fprintf (OutputFile, "\\addcontentsline{toc}{section}{%s}\n\n",
		           Chapter);
		  ForceCase (Dataset->AuthorBuffer, Title); 	   
		  fprintf (OutputFile, "\\markboth{%s}{%s}\n\n", 
		           Dataset->AuthorBuffer, Title);	   
		}	
	      break;
	    case MarkBeginSubtitle:
	      fprintf (OutputFile, "\\section*{\\raggedright ");
	      InChapter = 1;
	      break;
	    case MarkEndSubtitle:
	      fprintf (OutputFile, "}");
	      InChapter = 0;
	      break;
	    case MarkBeginTable:
	      InPreformatted = 1;
	      LastNewline = 0;
	      fprintf (OutputFile, "\\begin{verbatim}\n");
	      break;
	    case MarkEndTable:
	      InPreformatted = 0;
	      fprintf (OutputFile, "\\end{verbatim}\n");
	      break;
	    case MarkInsertMdash:
	      // The mbox really needs to be extended to cover the case of
	      // 2 or more adjacent mdashes (for example, in cases like
	      // "Lady ----- told us that ..."), but I'll leave that for
	      // another day.  I create a macro "\mdsh" and use it rather
	      // than "\mbox" because of problems with lyx.
	      if (Dataset->MdashSize != 3)
	        fprintf (OutputFile, "\\mdsh{");
	      for (i = 0; i < Dataset->MdashSize; i++)
	        {
	          fprintf (OutputFile, "-");
		  if (InChapter && ChapterNameSize < (sizeof (Chapter) - 1))
		    Chapter[ChapterNameSize++] = '-';
		}
	      if (Dataset->MdashSize != 3)	
	        fprintf (OutputFile, "}");	
	      break;
	    case MarkInsertNdash:
	      fprintf (OutputFile, "-");
	      if (InChapter && ChapterNameSize < (sizeof (Chapter) - 1))
		Chapter[ChapterNameSize++] = ' ';
	      break;
	    case MarkSoftHyphen:
	      // The only purpose for which soft-hyphens are presently
	      // used is to put them after an m-dash, to allow a 
	      // line-break there.  This seems necessary in HTML, but
	      // not in LaTeX, and just looks unnecessarily funny.
	      //fprintf (OutputFile, "\\-");
	      break;
	    case MarkJumpPastGutenbergHeader:
	      JumpedPastHeader = 1;
	      fprintf (OutputFile,
		       "\\chapter*{Project Gutenberg Fine Print}\\begin{verbatim}\n"
		       "\\markboth{%s}{Project Gutenberg Fine Print}\n",
		       Title);
	      SentPgHeader = 1;
	      break;
	    case MarkEndOfGutenbergHeader:
	      if (SentPgHeader == 1)
		fprintf (OutputFile, "\\end{verbatim}\n");
	      SentPgHeader = 0;
	      if (Dataset->LowestNonPrefatoryLine > 0)
		{
		  InPrefatoryArea = 1;
		  fprintf (OutputFile,
			   "\\chapter*{\\raggedright Prefatory Materials}\n"
			   "\\markboth{%s}{Prefatory Materials}\n", Title);
#if 0		  
		  fprintf (OutputFile,
			   "\\chapter*{\\raggedright Prefatory Materials}\n"
			   "\\markboth{%s}{Prefatory Materials}\n"
			   "\\begin{quotation}\n"
			   "\\textit{This is a modified "
			   "etext created by \\textbf{GutenMark} "
			   "software, version " __DATE__ ".", Title);
		  if (InputFilename != NULL)
		    fprintf (OutputFile,
			     " The original text was contained "
			     "in a computer file named \"%s.\"",
			     InputFilename);
		  fprintf (OutputFile, " Any comments below "
			   "about the preparation of the text "
			   "refer to the \\emph{original} "
			   "etext file, and do not directly "
			   "refer to this modified version of "
			   "the text. In particular, no individuals "
			   "named below bear any responsibility for "
			   "changes to the text.}\n" "\\end{quotation}\n");
#endif // 0			   
		}
	      break;
	    case MarkGutenbergEnder:
	      if (Dataset->YesHeader)
		{
		}
	      else
		AtEnd = 1;
	      break;
	    case MarkNoMoreMarks:
	      break;
	    }
	  ErrorCode = fread (&Mark, sizeof (Mark), 1, Dataset->MarkupFile);
	  if (ErrorCode != 1)
	    Mark.Type = MarkNoMoreMarks;
	}
      if (AtEnd)
	break;
      if (Remove)
	Remove = 0;
      else if (c == ' ')
        {
	  // 11/14/02 RSB.
	  if (lastc == (0x8000 | '~'))
	    {
	      // 11/22/02 RSB.
	      // There's no need to follow a ~ by a space.  We simply need
	      // to replace the ~ with the space.  NOTE: Originally I meant
	      // "~" here, but now I mean "\ ".
	      fseek (OutputFile, -lastcSize, SEEK_CUR);
	      fprintf (OutputFile, " ");
	    }
	  else if (lastc == ' ' || isalnum (lastc)
	      || lastc == ',' || lastc == ';')
	    fprintf (OutputFile, " ");
	  else  
	    {
	      //fprintf (OutputFile, "~");
	      if (lastc == (0x8000 | '~'))
	        {
		  lastcSize = 1;
	          fprintf (OutputFile, "~");
		}  
	      else
	        {
		  lastcSize = 2;
	          fprintf (OutputFile, "\\ ");
		}  
	      lastc = 0x8000 | '~';
	    }
	  if (InChapter && ChapterNameSize < (sizeof (Chapter) - 1))
	    {
	      Chapter[ChapterNameSize++] = ' ';
	    }
	}
      else
        {
	  if ((c == '\n' || c == '\r') && lastc == (0x8000 | '~'))
	    {
	      // 11/22/02 RSB.
	      fseek (OutputFile, -2, SEEK_CUR);
	      fprintf (OutputFile, " ");
	    }
          OutputChar (OutputFile, c, InChapter);	
	}
    }

  // What this does is to allow us to process any remaining markups that
  // are supposed to occur at the very end of the input (such as end of
  // paragraph.
  if (AtEnd == 0)
    {
      AtEnd = 1;
      goto LastShot;
    }

  // Last stage:  Close the output stream.          
  fprintf (OutputFile, "\\end{document}\n");

  return (0);
}
